import os
import ffmpeg
import subprocess
import asyncio
import aiofiles
import json
import hashlib
from typing import Optional, Dict, Any
from functools import lru_cache
import time

class VideoProcessor:
    """视频处理类，用于音视频分离"""
    
    def __init__(self):
        self.ffmpeg_path = 'ffmpeg'
        self.ffprobe_path = 'ffprobe'
        self.cache_dir = os.path.join(os.path.expanduser('~'), '.video_processor_cache')
        self.cache_file = os.path.join(self.cache_dir, 'video_info_cache.json')
        self.cache_ttl = 3600  # 缓存1小时
        
        # 确保缓存目录存在
        os.makedirs(self.cache_dir, exist_ok=True)
        
        # 内存缓存
        self._memory_cache = {}
        self._cache_timestamps = {}
    
    def _get_cache_key(self, file_path: str) -> str:
        """生成缓存键"""
        # 使用文件路径和修改时间的哈希作为缓存键
        try:
            stat = os.stat(file_path)
            key_data = f"{file_path}:{stat.st_mtime}:{stat.st_size}"
            return hashlib.md5(key_data.encode()).hexdigest()
        except:
            return hashlib.md5(file_path.encode()).hexdigest()
    
    def _is_cache_valid(self, cache_key: str) -> bool:
        """检查缓存是否有效"""
        if cache_key not in self._cache_timestamps:
            return False
        
        # 检查缓存是否过期
        return time.time() - self._cache_timestamps[cache_key] < self.cache_ttl
    
    def _save_to_cache(self, cache_key: str, data: Dict[str, Any]):
        """保存到内存缓存"""
        self._memory_cache[cache_key] = data
        self._cache_timestamps[cache_key] = time.time()
    
    def _load_from_cache(self, cache_key: str) -> Optional[Dict[str, Any]]:
        """从内存缓存加载"""
        if cache_key in self._memory_cache and self._is_cache_valid(cache_key):
            return self._memory_cache[cache_key]
        return None
    
    async def get_video_info_async(self, video_path: str) -> dict:
        """
        异步获取视频文件信息（带缓存）
        
        Args:
            video_path: 视频文件路径
            
        Returns:
            dict: 视频信息
        """
        cache_key = self._get_cache_key(video_path)
        
        # 尝试从内存缓存加载
        cached_data = self._load_from_cache(cache_key)
        if cached_data:
            return cached_data
        
        # 尝试从磁盘缓存加载
        try:
            async with aiofiles.open(self.cache_file, 'r', encoding='utf-8') as f:
                cache_data = json.loads(await f.read())
                if cache_key in cache_data and self._is_cache_valid(cache_key):
                    cached_data = cache_data[cache_key]
                    self._save_to_cache(cache_key, cached_data)
                    return cached_data
        except:
            pass
        
        # 缓存未命中，获取视频信息
        video_info = await self._get_video_info_raw_async(video_path)
        
        # 保存到缓存
        self._save_to_cache(cache_key, video_info)
        
        # 异步保存到磁盘缓存
        asyncio.create_task(self._save_to_disk_cache(cache_key, video_info))
        
        return video_info
    
    async def _get_video_info_raw_async(self, video_path: str) -> dict:
        """
        异步获取原始视频信息
        
        Args:
            video_path: 视频文件路径
            
        Returns:
            dict: 视频信息
        """
        # 首先尝试使用subprocess直接调用ffprobe
        try:
            cmd = [
                self.ffprobe_path,
                '-v', 'quiet',
                '-print_format', 'json',
                '-show_format',
                '-show_streams',
                video_path
            ]
            
            # 异步执行subprocess
            process = await asyncio.create_subprocess_exec(
                *cmd,
                stdout=asyncio.subprocess.PIPE,
                stderr=asyncio.subprocess.PIPE
            )
            
            stdout, stderr = await asyncio.wait_for(process.communicate(), timeout=10.0)
            
            if process.returncode != 0:
                raise Exception(f"ffprobe执行失败: {stderr.decode('utf-8', errors='ignore')}")
            
            if not stdout:
                raise Exception("ffprobe没有输出任何内容")
            
            probe = json.loads(stdout.decode('utf-8'))
            
            video_info = next(s for s in probe['streams'] if s['codec_type'] == 'video')
            audio_info = next((s for s in probe['streams'] if s['codec_type'] == 'audio'), None)
            
            return {
                'duration': float(probe['format']['duration']),
                'size': int(probe['format']['size']),
                'video_codec': video_info['codec_name'],
                'video_width': int(video_info['width']),
                'video_height': int(video_info['height']),
                'fps': eval(video_info['r_frame_rate']),
                'has_audio': audio_info is not None,
                'audio_codec': audio_info['codec_name'] if audio_info else None
            }
        except asyncio.TimeoutError:
            raise Exception(f"获取视频信息超时: {video_path}")
        except Exception as e:
            # 如果subprocess失败，回退到使用ffmpeg-python库
            try:
                # 在线程池中运行同步的ffmpeg.probe
                loop = asyncio.get_event_loop()
                probe = await loop.run_in_executor(None, ffmpeg.probe, video_path)
                
                video_info = next(s for s in probe['streams'] if s['codec_type'] == 'video')
                audio_info = next((s for s in probe['streams'] if s['codec_type'] == 'audio'), None)
                
                return {
                    'duration': float(probe['format']['duration']),
                    'size': int(probe['format']['size']),
                    'video_codec': video_info['codec_name'],
                    'video_width': int(video_info['width']),
                    'video_height': int(video_info['height']),
                    'fps': eval(video_info['r_frame_rate']),
                    'has_audio': audio_info is not None,
                    'audio_codec': audio_info['codec_name'] if audio_info else None
                }
            except Exception as fallback_error:
                raise Exception(f"获取视频信息失败 (subprocess: {str(e)}, fallback: {str(fallback_error)})")
    
    async def _save_to_disk_cache(self, cache_key: str, data: Dict[str, Any]):
        """异步保存到磁盘缓存"""
        try:
            # 读取现有缓存
            cache_data = {}
            try:
                async with aiofiles.open(self.cache_file, 'r', encoding='utf-8') as f:
                    cache_data = json.loads(await f.read())
            except:
                pass
            
            # 更新缓存
            cache_data[cache_key] = data
            
            # 清理过期缓存
            current_time = time.time()
            cache_data = {k: v for k, v in cache_data.items() 
                         if current_time - self._cache_timestamps.get(k, 0) < self.cache_ttl}
            
            # 保存到文件
            async with aiofiles.open(self.cache_file, 'w', encoding='utf-8') as f:
                await f.write(json.dumps(cache_data, ensure_ascii=False, indent=2))
        except Exception as e:
            print(f"保存缓存失败: {e}")
    
    def get_video_info(self, video_path: str) -> dict:
        """
        同步获取视频文件信息（保持向后兼容）
        
        Args:
            video_path: 视频文件路径
            
        Returns:
            dict: 视频信息
        """
        # 使用事件循环运行异步方法
        try:
            loop = asyncio.get_event_loop()
            if loop.is_running():
                # 如果事件循环正在运行，创建新的事件循环
                new_loop = asyncio.new_event_loop()
                asyncio.set_event_loop(new_loop)
                try:
                    return new_loop.run_until_complete(self.get_video_info_async(video_path))
                finally:
                    new_loop.close()
            else:
                return loop.run_until_complete(self.get_video_info_async(video_path))
        except RuntimeError:
            # 如果没有事件循环，创建一个
            loop = asyncio.new_event_loop()
            asyncio.set_event_loop(loop)
            try:
                return loop.run_until_complete(self.get_video_info_async(video_path))
            finally:
                loop.close()
    
    def check_ffmpeg_available(self) -> bool:
        """
        检查ffmpeg是否可用
        
        Returns:
            bool: ffmpeg是否可用
        """
        try:
            subprocess.run([self.ffmpeg_path, '-version'], 
                         capture_output=True, check=True)
            return True
        except (subprocess.CalledProcessError, FileNotFoundError):
            return False
    
    def extract_audio(self, video_path: str, output_path: str, 
                     audio_format: str = 'mp3', audio_bitrate: str = '192k') -> bool:
        """
        从视频中提取音频
        
        Args:
            video_path: 视频文件路径
            output_path: 输出音频文件路径
            audio_format: 音频格式 (mp3, aac, wav等)
            audio_bitrate: 音频比特率
            
        Returns:
            bool: 是否成功
        """
        try:
            # 确保输出目录存在
            os.makedirs(os.path.dirname(output_path), exist_ok=True)
            
            # 构建ffmpeg命令
            stream = ffmpeg.input(video_path)
            stream = ffmpeg.output(stream, output_path, 
                                 acodec='libmp3lame' if audio_format == 'mp3' else 'aac',
                                 ab=audio_bitrate)
            
            # 执行转换
            ffmpeg.run(stream, overwrite_output=True, quiet=True)
            return True
            
        except Exception as e:
            raise Exception(f"音频提取失败: {str(e)}")
    
    def convert_video(self, video_path: str, output_path: str, 
                     video_format: str = 'mp4', video_codec: str = 'libx264',
                     video_bitrate: str = None, target_resolution: str = None, 
                     video_info: dict = None) -> bool:
        """
        转换视频格式（无音频）
        
        Args:
            video_path: 输入视频文件路径
            output_path: 输出视频文件路径
            video_format: 视频格式
            video_codec: 视频编码器
            video_bitrate: 视频比特率（None表示保持原比特率）
            target_resolution: 目标分辨率 (widthxheight)
            
        Returns:
            bool: 是否成功
        """
        try:
            # 确保输出目录存在
            os.makedirs(os.path.dirname(output_path), exist_ok=True)
            
            # 添加调试信息
            print(f"[视频转换] 输入文件: {os.path.basename(video_path)}")
            print(f"[视频转换] 目标分辨率: {target_resolution}")
            print(f"[视频转换] 视频信息: {video_info}")
            
            # 构建ffmpeg命令
            stream = ffmpeg.input(video_path)
            
            # 准备输出参数
            output_params = {
                'an': None,  # 不包含音频
            }
            
            # 如果选择原分辨率，尽量保持原质量
            if not target_resolution or target_resolution == "原分辨率":
                # 保持原编码器（如果可能）
                output_params.update({
                    'vcodec': 'copy',  # 复制原视频流，不重新编码
                })
                print(f"[视频转换] 使用原分辨率模式: vcodec=copy")
            else:
                # 选择其他分辨率时，使用指定编码器
                resolution_params = self._get_resolution_params(target_resolution, video_info)
                output_params.update({
                    'vcodec': video_codec,
                    'vb': video_bitrate or '2000k',
                    **resolution_params
                })
                print(f"[视频转换] 使用指定分辨率模式: {resolution_params}")
            
            # 只提取视频流，不包含音频
            stream = ffmpeg.output(stream, output_path, **output_params)
            
            # 执行转换
            ffmpeg.run(stream, overwrite_output=True, quiet=True)
            print(f"[视频转换] 转换完成: {os.path.basename(output_path)}")
            return True
            
        except Exception as e:
            # 如果复制失败，尝试重新编码
            try:
                stream = ffmpeg.input(video_path)
                stream = ffmpeg.output(stream, output_path,
                                     vcodec=video_codec,
                                     vb=video_bitrate or '2000k',
                                     an=None,
                                     **self._get_resolution_params(target_resolution, video_info))
                ffmpeg.run(stream, overwrite_output=True, quiet=True)
                return True
            except Exception as e2:
                raise Exception(f"视频转换失败: {str(e2)}")
    
    def _get_resolution_params(self, target_resolution: str, video_info: dict = None) -> dict:
        """
        获取分辨率参数，根据原视频方向确定目标分辨率
        
        Args:
            target_resolution: 目标分辨率字符串
            video_info: 视频信息（包含原始宽高）
            
        Returns:
            dict: ffmpeg参数
        """
        print(f"[分辨率参数] 目标分辨率: {target_resolution}")
        print(f"[分辨率参数] 视频信息: {video_info}")
        
        if not target_resolution or target_resolution == "原分辨率":
            print(f"[分辨率参数] 返回空参数（原分辨率）")
            return {}
        
        # 解析目标分辨率（根据原视频方向确定具体尺寸）
        resolution_map = {
            "4K": {"landscape": (3840, 2160), "portrait": (2160, 3840)},
            "2K": {"landscape": (2560, 1440), "portrait": (1440, 2560)}, 
            "1080p": {"landscape": (1920, 1080), "portrait": (1080, 1920)},
            "720p": {"landscape": (1280, 720), "portrait": (720, 1280)},
            "480p": {"landscape": (854, 480), "portrait": (480, 854)}
        }
        
        if target_resolution in resolution_map:
            # 如果有原视频信息，根据原视频方向选择目标尺寸
            if video_info and 'video_width' in video_info and 'video_height' in video_info:
                original_width = video_info['video_width']
                original_height = video_info['video_height']
                print(f"[分辨率参数] 原始尺寸: {original_width}x{original_height}")
                
                # 判断原视频方向
                is_original_landscape = original_width > original_height
                orientation = "landscape" if is_original_landscape else "portrait"
                print(f"[分辨率参数] 原视频方向: {'横屏' if is_original_landscape else '竖屏'}")
                
                # 根据原视频方向选择目标尺寸
                target_width, target_height = resolution_map[target_resolution][orientation]
                print(f"[分辨率参数] 目标尺寸: {target_width}x{target_height}")
                
                # 按比例缩放，保持宽高比
                aspect_ratio = original_width / original_height
                if aspect_ratio > 1:  # 横向视频
                    new_width = target_width
                    new_height = int(target_width / aspect_ratio)
                else:  # 纵向视频
                    new_height = target_height
                    new_width = int(target_height * aspect_ratio)
                
                # 确保尺寸是偶数
                if new_width % 2 != 0:
                    new_width += 1
                if new_height % 2 != 0:
                    new_height += 1
                
                # 检查计算结果是否合理
                if new_width < 100 or new_height < 100:
                    print(f"[分辨率参数] 警告：计算结果过小 ({new_width}x{new_height})，使用固定分辨率")
                    result = {'vf': f'scale={target_width}:{target_height}:flags=lanczos'}
                else:
                    result = {'vf': f'scale={new_width}:{new_height}:flags=lanczos'}
                
                print(f"[分辨率参数] 计算结果: {result}")
                return result
            else:
                # 没有原视频信息，默认使用横屏尺寸
                target_width, target_height = resolution_map[target_resolution]["landscape"]
                result = {'vf': f'scale={target_width}:{target_height}:flags=lanczos'}
                print(f"[分辨率参数] 使用默认横屏分辨率: {result}")
                return result
        
        print(f"[分辨率参数] 未找到匹配的分辨率，返回空参数")
        return {}
    
    def process_video(self, video_path: str, output_folder: str, file_manager, 
                     target_resolution: str = "原分辨率", save_audio: bool = True,
                     save_video: bool = True, save_subtitles: bool = False,
                     remove_subtitles: bool = False, remove_hardcoded_subtitles: bool = False) -> dict:
        """
        处理单个视频文件：分离音视频并保存到指定格式
        
        Args:
            video_path: 视频文件路径
            output_folder: 输出文件夹
            file_manager: 文件管理器实例
            target_resolution: 目标分辨率
            save_audio: 是否保存音频
            save_video: 是否保存视频
            save_subtitles: 是否保存字幕
            remove_subtitles: 是否移除内嵌字幕
            remove_hardcoded_subtitles: 是否移除硬编码字幕
            
        Returns:
            dict: 处理结果
        """
        try:
            # 获取视频信息
            video_info = self.get_video_info(video_path)
            
            # 检测字幕信息
            subtitle_info = self.get_subtitle_info(video_path)
            print(f"  字幕检测结果: {subtitle_info}")
            
            # 生成输出文件名
            base_name = file_manager.generate_filename(video_path)
            
            # 音频输出路径
            audio_output = os.path.join(output_folder, 'audio', f"{base_name}.mp3")
            
            # 视频输出路径
            video_output = os.path.join(output_folder, 'video', f"{base_name}.mp4")
            
            # 字幕输出路径
            subtitle_output = os.path.join(output_folder, 'subtitles', f"{base_name}.srt")
            
            result = {
                'input_file': video_path,
                'audio_output': audio_output if save_audio else None,
                'video_output': video_output if save_video else None,
                'subtitle_output': subtitle_output if save_subtitles else None,
                'success': True,
                'errors': []
            }
            
            # 提取音频
            if save_audio and video_info['has_audio']:
                try:
                    self.extract_audio(video_path, audio_output)
                    result['audio_extracted'] = True
                except Exception as e:
                    result['audio_extracted'] = False
                    result['errors'].append(f"音频提取失败: {str(e)}")
            elif save_audio and not video_info['has_audio']:
                result['audio_extracted'] = False
                result['errors'].append("视频文件没有音频轨道")
            else:
                result['audio_extracted'] = False
            
            # 转换视频（无音频）
            if save_video:
                try:
                    if remove_subtitles or remove_hardcoded_subtitles:
                        # 使用去字幕功能
                        self.remove_subtitles(video_path, video_output, 
                                            remove_embedded=remove_subtitles,
                                            remove_hardcoded=remove_hardcoded_subtitles)
                        result['video_converted'] = True
                        result['subtitles_removed'] = True
                    else:
                        # 正常转换视频
                        self.convert_video(video_path, video_output, target_resolution=target_resolution, video_info=video_info)
                        result['video_converted'] = True
                except Exception as e:
                    result['video_converted'] = False
                    result['errors'].append(f"视频转换失败: {str(e)}")
            else:
                result['video_converted'] = False
            
            # 提取字幕
            if save_subtitles:
                try:
                    subtitle_info = self.get_subtitle_info(video_path)
                    if subtitle_info['has_subtitles']:
                        # 提取第一个字幕流
                        self.extract_subtitles(video_path, subtitle_output)
                        result['subtitle_extracted'] = True
                    else:
                        result['subtitle_extracted'] = False
                        # 不将"没有字幕流"作为错误，这是正常情况
                        print(f"  注意: 视频文件没有字幕流")
                except Exception as e:
                    result['subtitle_extracted'] = False
                    result['errors'].append(f"字幕提取失败: {str(e)}")
            else:
                result['subtitle_extracted'] = False
            
            # 检查整体成功状态
            success_conditions = []
            
            if save_audio:
                if video_info['has_audio']:
                    success_conditions.append(result['audio_extracted'])
                else:
                    success_conditions.append(True)  # 没有音频但不需要保存，算成功
            
            if save_video:
                success_conditions.append(result['video_converted'])
            
            # 字幕提取失败不影响整体成功状态，因为可能视频本身就没有字幕
            # 只要音频和视频处理成功就算成功
            
            # 如果没有任何保存选项，默认成功
            if not success_conditions:
                result['success'] = True
            else:
                result['success'] = all(success_conditions)
            
            # 添加调试信息
            print(f"处理文件: {os.path.basename(video_path)}")
            print(f"  保存选项: 音频={save_audio}, 视频={save_video}, 字幕={save_subtitles}")
            print(f"  字幕处理: 移除内嵌={remove_subtitles}, 移除硬编码={remove_hardcoded_subtitles}")
            print(f"  有音频: {video_info['has_audio']}")
            print(f"  音频提取: {result['audio_extracted']}")
            print(f"  视频转换: {result['video_converted']}")
            print(f"  字幕提取: {result.get('subtitle_extracted', False)}")
            print(f"  最终结果: {result['success']}")
            if result['errors']:
                print(f"  错误信息: {result['errors']}")
            if save_audio:
                print(f"  音频输出: {audio_output}")
            if save_video:
                print(f"  视频输出: {video_output}")
            if save_subtitles:
                print(f"  字幕输出: {subtitle_output}")
            print("---")
            
            return result
            
        except Exception as e:
            return {
                'input_file': video_path,
                'success': False,
                'errors': [f"处理失败: {str(e)}"]
            }
    
    def batch_process(self, video_files: list, output_folder: str, file_manager,
                     progress_callback: Optional[callable] = None) -> list:
        """
        批量处理视频文件
        
        Args:
            video_files: 视频文件路径列表
            output_folder: 输出文件夹
            file_manager: 文件管理器实例
            progress_callback: 进度回调函数
            
        Returns:
            list: 处理结果列表
        """
        results = []
        total_files = len(video_files)
        
        for i, video_file in enumerate(video_files):
            try:
                # 处理单个文件
                result = self.process_video(video_file, output_folder, file_manager)
                results.append(result)
                
                # 调用进度回调
                if progress_callback:
                    progress = (i + 1) / total_files * 100
                    progress_callback(progress, result)
                    
            except Exception as e:
                results.append({
                    'input_file': video_file,
                    'success': False,
                    'errors': [f"处理失败: {str(e)}"]
                })
        
        return results 
    
    def remove_subtitles(self, video_path: str, output_path: str, 
                        remove_embedded: bool = True, remove_hardcoded: bool = False,
                        hardcoded_area: tuple = None) -> bool:
        """
        从视频中移除字幕
        
        Args:
            video_path: 输入视频文件路径
            output_path: 输出视频文件路径
            remove_embedded: 是否移除内嵌字幕流
            remove_hardcoded: 是否移除硬编码字幕
            hardcoded_area: 硬编码字幕区域 (x, y, width, height)，None表示自动检测
            
        Returns:
            bool: 是否成功
        """
        try:
            # 确保输出目录存在
            os.makedirs(os.path.dirname(output_path), exist_ok=True)
            
            # 构建ffmpeg命令
            stream = ffmpeg.input(video_path)
            
            # 准备输出参数
            output_params = {}
            
            if remove_hardcoded:
                # 移除硬编码字幕（使用delogo滤镜）
                if hardcoded_area:
                    x, y, width, height = hardcoded_area
                    stream = ffmpeg.filter(stream, 'delogo', x=x, y=y, w=width, h=height)
                else:
                    # 自动检测字幕区域（通常在底部）
                    stream = ffmpeg.filter(stream, 'delogo', x=0, y='ih-60', w='iw', h=60)
                
                # 使用滤镜时需要重新编码
                output_params.update({
                    'vcodec': 'libx264',
                    'acodec': 'aac'
                })
                
                # 如果同时移除内嵌字幕，只映射视频和音频流
                if remove_embedded:
                    output_params['map'] = ['0:v', '0:a']
                else:
                    # 保留所有流，但视频会被重新编码
                    pass
                    
            elif remove_embedded:
                # 只移除内嵌字幕流：只保留视频和音频流
                output_params.update({
                    'map': ['0:v', '0:a'],  # 只映射视频和音频流
                    'c': 'copy'  # 复制流，不重新编码
                })
            
            # 输出
            stream = ffmpeg.output(stream, output_path, **output_params)
            
            # 执行转换
            try:
                ffmpeg.run(stream, overwrite_output=True, quiet=True)
                return True
            except ffmpeg.Error as e:
                # 如果去字幕失败，尝试正常转换
                print(f"  去字幕处理失败，尝试正常转换: {e}")
                return self.convert_video(video_path, output_path, video_info=self.get_video_info(video_path))
            
        except Exception as e:
            raise Exception(f"移除字幕失败: {str(e)}")
    
    def extract_subtitles(self, video_path: str, output_path: str, 
                         subtitle_format: str = 'srt', subtitle_index: int = 0) -> bool:
        """
        从视频中提取字幕
        
        Args:
            video_path: 输入视频文件路径
            output_path: 输出字幕文件路径
            subtitle_format: 字幕格式 (srt, ass, vtt等)
            subtitle_index: 字幕流索引
            
        Returns:
            bool: 是否成功
        """
        try:
            # 确保输出目录存在
            os.makedirs(os.path.dirname(output_path), exist_ok=True)
            
            # 构建ffmpeg命令
            stream = ffmpeg.input(video_path)
            
            # 提取字幕流
            stream = ffmpeg.output(stream, output_path, 
                                 map=f'0:s:{subtitle_index}',
                                 f=subtitle_format)
            
            # 执行转换
            ffmpeg.run(stream, overwrite_output=True, quiet=True)
            return True
            
        except Exception as e:
            raise Exception(f"提取字幕失败: {str(e)}")
    
    def get_subtitle_info(self, video_path: str) -> dict:
        """
        获取视频中的字幕信息
        
        Args:
            video_path: 视频文件路径
            
        Returns:
            dict: 字幕信息
        """
        try:
            # 使用ffprobe获取字幕流信息
            probe = ffmpeg.probe(video_path)
            
            subtitle_streams = []
            for i, stream in enumerate(probe['streams']):
                if stream['codec_type'] == 'subtitle':
                    subtitle_info = {
                        'index': i,
                        'codec_name': stream.get('codec_name', 'unknown'),
                        'language': stream.get('tags', {}).get('language', 'unknown'),
                        'title': stream.get('tags', {}).get('title', f'Subtitle {i}'),
                        'codec_type': stream['codec_type']
                    }
                    subtitle_streams.append(subtitle_info)
            
            return {
                'has_subtitles': len(subtitle_streams) > 0,
                'subtitle_count': len(subtitle_streams),
                'subtitle_streams': subtitle_streams
            }
            
        except Exception as e:
            raise Exception(f"获取字幕信息失败: {str(e)}") 